home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
asm_kit
/
host.asm
< prev
next >
Wrap
Assembly Source File
|
1985-11-06
|
17KB
|
386 lines
PAGE 66,132
TITLE HOST - Link communication device to console using interrupts
;
; Program to install resident communications interrupt driver,
; and link it into the keyboard/video interrupt routines.
;
; We must define a general interrupt handler for the COM1 port,
; which will input characters directly into BIOS's keyboard input
; (typeahead) buffer. This buffer is defined by pointers at offset
; 001A (start of buffer pointer), and 001C (end of buffer pointer).
; The data segment for all of this is 0040. There is a BIOS routine
; at F000:E875 which handles a 15-char circular buffer wrap-around.
; We should copy it. We must compare [001A] with [001C] after calling
; the buffer wrap routine to see if the buffer full. If so, it'd
; be nice to send a bell to the caller, but im not sure this is the
; place to do it (inside an interrupt routine).
;
; Note that we assume the COM1 port is already initialized (RS232 stuff)
;
; Note that this routine must also detect change of line status and
; have appropriate logic for indicating and handling loss of carrier,
; and other delta indications in the line status register.
;
; This takes care of the keyboard input end of the communication
; interface.
;
; For linking screen output, I guess we just intercept the old
; screen output 'interrupt' vector, located at 0000:0040-:0043.
; There is no reason to buffer the output, so the intercept routine
; will first output the byte to the UART (if UART accepting), then
; pass control on to the former screen handler.
;
; The record-type HOSTFLAGS contains duplex, CR/LF, bell enable, and
; timeout specification. Timeout determines iff forced disconnect for
; lack of user input enablad.
hostflags record duplex:1,crlf:1,bell:1,cls:1,timeout:1
discflags record rlsd:1,ri:1,dsr:1,cts:1
;
comment %
; Structure HOSTCB contains terminal setting values:
hostcb struc
clsequence db 0,12 ; default cls sequence
timeout_at db 128 ; halfway through the timeout scale default
baudrate_lsb db 80h
baudrate_msb db 1 ; default UART baud rate = 300 baud
userid dt ? ; ten bytes? for user identification
screen_size db 24 ; # of lines on screen
screen_width db 80 ; # of chars per line on screen
hostcb ends
;
%
;
inport macro port
lea dx,port ; get port offset into dx
in al,dx
endm
;
outport macro port
lea dx,port ; get port offset into dx
out dx,al
endm
;
; Set up references to the system interrupt vector table:
;
;
int_table segment at 0h
org 10H*4 ; address of video driver vector
int10 label word
org 0CH*4 ; address of comm interrupt vector
int0c label word
int_table ends
;
; Set up references to BIOS keyboard and COM system table.
;
;
sys_table segment at 40h
rs232_base dw 4 dup(?)
org 1Ah
buffer_head dw ?
buffer_tail dw ?
kb_buffer dw 16 dup(?)
kb_buffer_end label word
org 71h
bios_break db ?
sys_table ends
;
;
comgrp group host,com_init
;
host segment
assume cs:comgrp
;
; Proc to bump BIOS's keyboard buffer pointer, in DI.
advance_kb proc far
add di,2
cmp di,offset kb_buffer_end
jnz noneed
mov di,offset kb_buffer ; wrap if at end of buffer
noneed: ret
advance_kb endp
;
eoi equ 20h ; end of interrupt value for 8259 controller
;
baud_data equ 0[BX] ; baud rate selector and data register in UART
baud_msb_int equ 1[BX] ; baud rate selector MSB and interrupt enable
interrupt_id equ 2[BX] ; interrupt identification register
line_control equ 3[BX] ; line control register
modem_control equ 4[BX] ; modem control register
line_status equ 5[BX] ; line status register
modem_status equ 6[BX] ; modem status register
;
comint proc far
assume cs:comgrp,ds:sys_table
sti
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
mov ax,sys_table ; point to system table segment
mov ds,ax
mov bx,rs232_base ; get base port for COM1 device
;
; Begin code to interrogate interrupt situation: "Why were we called ?"
;
; Note that we have set interrupts for change in modem status, and
; receiver data-ready. This means either he hung up (or ?) or he
; just sent us a character. The interrupt-id register will tell us which.
;
inport interrupt_id ; read the interrupt id register
shr al,1 ; of course an interrupt occurred!
and al,00000011b ; lower 2 bits active.
jz delta_stat ; go interpret change in modm stat
dec al ; test for transmitter hold empty.
jz no_action ; we're not processing these here.
dec al ; test for received char?
jz get_com_char ; read char from com device.
dec al ; Break or error received.
jz brk_rcd
no_action: mov al,eoi ; end-of-inerrupt code to al
out 20h,al ; tell controller to cancel interrupt
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret ; return to previous task.
;
; Break was received (or there was a line error)
; IF break received, simulate console CONTROL-BREAK function.
;
brk_rcd: inport line_status
and al,00010000b ; break detected ?
jz no_action ; we're ignoring other errors now.
mov di,offset kb_buffer ; load kb_buffer start
mov buffer_head,di ; reset buffer to empty
mov buffer_tail,di
mov bios_break,80h ; set break byte.
int 1bh ; do break service
jmp no_action ; return ourselves
;
get_com_char: inport baud_data ; read byte from port
mov di,buffer_tail ; end of kb buff
mov si,di ; store it
call advance_kb ; try to make space for it
cmp di,buffer_head ; has buffer wrapped ?
jz kb_full ; buffer full!
xor ah,ah ; convert al -> ax
mov [si],ax ; store it in BIOS keyboard buffer
mov buffer_tail,di ; update buffer
jmp no_action ; return to caller
;
kb_full: jmp no_action ; we'll eventually BEEP the user here.
;
delta_stat: inport modem_status
mov cs:c_modem_status,al ; remember new modem status
jmp no_action
;
comint endp
;
;
console_out proc far
assume cs:host,ds:sys_table
jmp begin_console ; jump around ID field
console_id: db 'HOST' ; our identification field
begin_console: cmp ah,14 ; is it 'print tty' function ?
jz take_over ; yes, intercept it
cmp ah,10 ; it is 'print over char' function ?
jz take_over ; yes, lets intercept it too
normal_tty: jmp cs:old_int10 ; go to normal int 10 handler
take_over: push ax
push di
push si
push dx
push bx
push cx
push ds
test cs:c_modem_status,10000000b ; is there a connection?
jz bypass_user ; no, we wont try to send
mov cl,al ; save value for output
mov ax,sys_table
mov ds,ax ; prepare to examine UART
mov bx,rs232_base ; get base address of com port
send_char: inport line_status ; see if ready to send byte.
and al,00100000b ; test xmit hold reg empty ?
jz send_char ; no, wait for it
mov al,cl ; get back char to send
outport baud_data ; output byte to com1 iff ready
bypass_user: pop ds
pop cx
pop bx
pop dx
pop si
pop di
pop ax
jmp normal_tty
;
console_out endp
;
old_int10 dd ? ; doubleword pointer to old int10
;
; Set up our internal status flags:
c_modem_status discflags <?,?,?,?>
; Set up user parm area
user_flags hostflags <1,1,1,1,1> ; user logon and termninal flags
user_disc discflags <1,0,1,0> ; lines for continual test/disconnect
;user_parms hostcb <,,,,,,> ; user logon and terminal characteristics
user_parms equ $
;
; Structure HOSTCB contains terminal setting values:
clsequence db 0,12 ; default cls sequence
timeout_at db 128 ; halfway through the timeout scale default
baudrate_lsb db 80h
baudrate_msb db 1 ; default UART baud rate = 300 baud
userid dt ? ; ten bytes? for user identification
screen_size db 24 ; # of lines on screen
screen_width db 80 ; # of chars per line on screen
;
end_com equ this byte ; return to dos, stay res.
;
host ends
;
com_init segment
assume cs:com_init,ds:sys_table,es:comgrp
host_init proc far
;
; We'll assume that the UART has been initialized for now
; we will install the interrupt driven keyboard link and
; the INT 10H intercept driver.
;
cli ; off ints so dont get caught
push ds ; save pointer to dos psp
mov ax,50h ; offset to int21 in psp
push ax
mov ax,host ; point to driver segment
mov es,ax
mov ax,sys_table ; point to system table
mov ds,ax
mov bx,rs232_base ; get base of port addresses
inport modem_status
mov es:c_modem_status,al ; initialize out record of it
mov al,00001011b ; set MCR for interrupts
outport modem_control
mov al,00001101b ; desired interrupt fields
outport baud_msb_int ; enable those interrupts
mov ax,int_table ; get interrupt table segment
mov ds,ax
assume ds:int_table
mov dx,int10 ; get offset for old int10
push dx
push bx
push ds
xchg bx,dx ; put offset into bx
mov ax,host ; address ID field
mov ds,ax
mov dx,[bx+3] ; look at our ID field1
cmp dx,'HO' ; Could it be us ?
jnz notus ; nop.
mov dx,[bx+5] ; Look at field 2 to be sure
cmp dx,'ST'
notus: pop ds
pop bx
pop dx
jnz itsok
jmp reject_init ; We were already installed
itsok: mov es:old_int10,dx ; fill in
mov dx,int10+2 ; get segment for old int10
mov es:old_int10+2,dx ; fill in
mov dx,host ; get new seg for int10
mov int10+2,dx ; store it
mov dx,offset console_out ; get new offset for int10
mov int10,dx ; store it
mov dx,host ; get new seg for int0c
mov int0c+2,dx ; store it
mov dx,offset comint ; and offset
mov int0c,dx ; and offset
in al,21h ; read from IMR
and al,0efh ; turn off b4=enable comm interrupts
out 21h,al ; in 8259 controller
mov al,0 ; retcode = 0
mov dx,offset comgrp:end_com; point to end of program
mov cl,4 ; for devide by 16
shr dx,cl ; turn into # segments
add dx,100 ; leave 1K for dos environ ????
mov ah,31h ; tell DOS to save this pgm.
jmp ok_init ; successful initialization
;
exit_init: ret ; far ret to dos function call
;
ok_init: sti ; re-enable the interrupts
; call print_inline
; db 'pcHOST 1.0 - 09/29/83 - M.R.',13,10
; db 'Communication console link loaded and initialized.'
; db 13,10,10,0
jmp exit_init
;
reject_init: sti ; re-enable the interrupts
; call print_inline
; db 'HOST driver is already installed.',13,10
; db 'Nothing done.',13,10,0
; pop ax ; pop off 'stay resident' return
; xor ax,ax ; make 'terminate overlay' return
; push ax
jmp exit_init
;
; Print_Inline proc: Prints ASCIIZ text at offset on NEAR STACK.
; Returns to address following delimiting zero of ASCIIZ string.
; Resgisters destroyed: SI.
print_inline proc
pop si
push ax
check_char: mov al,[si]
inc si
or al,al
jz msg_done
call print_chr
jmp check_char
msg_done: pop ax ; get back ax
push si ; is this the ONLY way to jump
ret ; to an address pointed to by SI ?
print_inline endp
;
; Print_Chr proc: prints char in AL via INT 10H.
; Registers destroyed: AX.
print_chr proc
mov ah,14 ; and AH for PRINT TTY function
call int_10h ; print char to tty
ret
print_chr endp
;
; INT_10H proc: Intercept to the BIOS INT 10H
; but saving all registers. Also, set BX=0 to select current
; screen page. All registers except BX must be set prior call.
; Registers destroyed: None.
int_10h proc
push bx
push ax
mov bx,0 ; select screen zero
push bp
push di
push si
int 10h
pop si
pop di
pop bp
pop ax
pop bx
ret
int_10h endp
;
host_init endp
com_init ends
;
;
end host_init